/* qirssi
 * Copyright (c) 2009 Paulo Matias
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Purpose: Implementation of the CommandProcessor class
 *          and code to setup a Unix Domain Socket.
 */

#include <QString>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#include "commandprocessor.h"
#include "main.h"

/*
 * Setups a Unix Domain Socket in "~/.irssi/qirssi.sock".
 */
static int setup_socket() {
    struct sockaddr_un addr;
    int sock;

    assert((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0);

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;

    char *home_path = getenv("HOME");
    assert(home_path && (strlen(home_path) > 0));

    strncpy(addr.sun_path, home_path, sizeof(addr.sun_path));
    strncat(addr.sun_path, "/.irssi/qirssi.sock", sizeof(addr.sun_path));

    unlink(addr.sun_path);

    assert(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) >= 0);

    return sock;
}

/*
 * Creates a socket using setup_socket() and
 * plugs it into a itself (a QSocketNotifier).
 */
CommandProcessor::CommandProcessor(QObject *parent)
    :QSocketNotifier(setup_socket(), Read, parent)
{
     connect(this, SIGNAL(activated(int)), this, SLOT(data_arrived(int)));
}

/*
 * This is called when data can be read from the socket.
 */
void CommandProcessor::data_arrived(int sock) {
    /* Receive data from the socket */
    char buf[2048];
    int len = recv(sock, buf, sizeof(buf)-1, 0);

    /* Check if data was received without errors. */
    if(len > 0) {
        /* The App object is our parent. Get it. */
        App *a = dynamic_cast<App*>(parent());
        assert((a != NULL));

        /* Put a zero termination into the string. */
        buf[len] = '\0';

        /* Split at the first space and get the command name. */
        char *saveptr, *cmd;
        cmd = strtok_r(buf, " \t\n", &saveptr);

        if(!strcmp(cmd, "show")) {
            /* Command "show title msg". */
            char *title = strtok_r(NULL, " \t\n", &saveptr);
            char *msg = strtok_r(NULL, "", &saveptr);
            a->trayicon->showMessage(QString::fromUtf8(title), QString::fromUtf8(msg));
        }
        else if(!strcmp(cmd, "icon")) {
            /* Command "icon on" or "icon off". */
            char *arg = strtok_r(NULL, "", &saveptr);
            if(!strcmp(arg, "on")) {
                a->trayicon->setIcon(*a->icon_on);
            }
            else if(!strcmp(arg, "off")) {
                a->trayicon->setIcon(*a->icon_off);
            }
        }
    }
}

